volatile含有部分synchronized的特性,效率更高,但使用时需要注意细节,不然容易出错
是什么
Java中被volatile修饰的变量,每次读写都会直接使用“内存”介质,而不是使用CPU缓存
音 — UK /ˈvɒl.ə.taɪl/ US /ˈvɑː.lə.t̬əl/
英 — likely to change suddenly and unexpectedly or suddenly become violent or angry
中 — 易变的
特性
- 保证变量可见性
- 禁止指令进行重排序
基础概念:可见性、有序性、原子性
- 可见性:对所有线程来说,任一线程对变量的改动都立即可见
- 有序性:代码可能会被编译器混编,有序性即指代码按顺序执行
- 原子性:所有操作不会被打断,谁也不行(除非断电)
实际上我们对变量的修改,虽然可能Java就一行代码(如 y=x),但被解释成汇编语言会变成多行(y=x就需要进行两步操作:读x值,写入y所在内存,学过汇编的同学应该比较清楚)
与synchronized的区别
按字面理解,volatile关键字只是标记变量为易变的,并不能保证对变量的所有操作都是同步的,即不能保证具有synchronized一样的效果
实际上,对volatile修饰的变量的读/写操作是可以保证其原子性的,但还要注意一个问题,即同时写变量的线程可能不止一个,如此一来,其中部分的写操作就有可能丢失
听起来好像volatile使用起来很危险,但它也是有它的用途的
用法
- 对于写不依赖历史状态的变量,可以考虑使用volatile修饰字代替synchronized来提高程序效率
- 保证代码的有序性:volatile变量的读写操作之前的代码,编译器是不会进行重排序的
小结
在volatile满足不了要求的场景可以考虑使用synchronized、lock、Atomic变量来保证特性
对变量的写不依赖历史状态的变量使用volatile修饰可以提高效率
对于需要保证部分程序语句有序性的场景可以考虑使用volatile代替锁定整个代码块,提高效率